#pragma once
#include <netinet/in.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <cstring>
#include "log.h"
#include "data_segment.h"
#include "packet_statistics.h"
#include "sliding_window.h"

#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <algorithm>
#include <cmath>
#include <sstream>
#include <vector>
namespace safe_udp
{
    class UdpServer
    {
    public:
        UdpServer();

        // lg(Info, "accept success ,%s:%d", clientip.c_str(), clientport);
        // 服务器启动
        int StartServer(int port);

        // 监听客户端请求
        char *GetRequest(int client_sockfd);

        // 打开文件
        bool OpenFile(const std::string &file_name);

        // 开始文件传输
        void StartFileTransfer();

        // 发送错误信息
        void SendError();

        int rwnd_;              // 接收窗口大小
        int cwnd_;              // 拥塞窗口大小
        int ssthresh_;          // 慢启动门限
        int start_byte_;        // 表征当前要发送数据包的起始字节
        bool is_slow_start_;    // 是否处于慢启动状态
        bool is_cong_avd_;      // 是否处于拥塞避免状态
        bool is_fast_recovery_; // 是否处于快速恢复状态

    private:
        std::unique_ptr<SlidingWindow> sliding_window_;       // 管理滑动窗口对象的指针
        std::unique_ptr<PacketStatistics> packet_statistics_; // 管理数据包统计对象

        PacketStatistics p;
        int sockfd_;
        std::fstream file_;              // 文件流对象
        struct sockaddr_in cli_address_; // 客户端地址
        int initial_seq_number_;         // 初始序号
        int file_length_;                // 文件长度
        double smoothed_rtt_;            // 平滑往返时间
        double dev_rtt_;// 往返时间差
        
        double smoothed_timeout_; // 平滑超时时间

        // 发送过程
        void send();

        // 定位发送哪个数据包
        void send_packet(int seq_number, int start_byte);

        // 重发文件的哪部分数据
        void read_file_and_send(bool fin_flag, int start_byte, int end_byte);

        // 重发数据段
        void send_data_segment(DataSegment *data_segment);

        // 等待确认，根据确认情况（丢包或全部确认收到）执行对应的逻辑
        void wait_for_ack();

        // 计算超时时间
        void calculate_rtt_and_time(struct timeval start_time, struct timeval end_time);

        // 哪个数据包需要快重传
        void retransmit_segment(int index_number);
    };
} // namespace safe_udp